package xxl.signals.impl 
{
	import xxl.signals.api.IOnceSignal;
	import xxl.signals.api.ISlot;
	
	/**
	 * @author XXL
	 */
	public class Slot implements ISlot 
	{
		public static var DEBUG_MODE:Boolean = false;
		
		protected var _signal:IOnceSignal;
		protected var _listener:Function;
		protected var _once:Boolean = false;
		protected var _priority:int = 0;
		protected var _enabled:Boolean = true;
		protected var _params:Array;
		protected var _safelyExecute:Boolean = false;
		protected var _debug:Boolean;
		
		public function Slot(listener:Function, signal:IOnceSignal, once:Boolean = false, priority:int = 0) 
		{
			_listener = listener;
			_signal = signal;
			_once = once;
			_priority = priority;
			
			verifyListener(listener);
			_debug = DEBUG_MODE;
		}
		
		protected function verifyListener(listener:Function):void
		{
			if (null == listener)
			{
				throw new ArgumentError("listener不能为空");
			}
			if (null == _signal)
			{
				throw new ArgumentError("signal不能为空");
			}
		}
		
		/* INTERFACE xxl.signals.core.ISlot */
		
		public function get listener():Function 
		{
			return _listener;
		}
		
		public function set listener(value:Function):void 
		{
			verifyListener(value);
			_listener = value;
		}
		
		public function get once():Boolean 
		{
			return _once;
		}
		
		public function get params():Array 
		{
			return _params;
		}
		
		public function set params(value:Array):void 
		{
			_params = value;
		}
		
		public function get priority():int 
		{
			return _priority;
		}
		
		public function get enabled():Boolean 
		{
			return _enabled;
		}
		
		public function set enabled(value:Boolean):void 
		{
			_enabled = value;
		}
		/**
		 * 提升5%左右性能。。。
		 * @param	valueObjects
		 */
		public function executeTree(valueObjects:Array):void
		{
			if (!_enabled)
			{
				return;
			}
			if (_once)
			{
				remove();
			}
			if (_params && _params.length)
			{
				valueObjects = valueObjects.concat(_params);
			}
			const numValueObjects:int = valueObjects.length;
			if (numValueObjects < 6)
			{
				if (numValueObjects < 3)
				{
					if (numValueObjects == 0)
					{
						_listener();
					}
					else if (numValueObjects == 1)
					{
						_listener(valueObjects[0]);
					}
					else
					{
						_listener(valueObjects[0], valueObjects[1]);
					}
				}
				else
				{
					if (numValueObjects == 3)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2]);
					}
					else if (numValueObjects == 4)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3]);
					}
					else
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4]);
					}
				}
			}
			else
			{
				if (numValueObjects < 9)
				{
					if (numValueObjects == 6)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5]);
					}
					else if (numValueObjects == 7)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6]);
					}
					else if (numValueObjects == 8)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7]);
					}
				}
				else
				{
					if (numValueObjects == 9)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7], valueObjects[8]);
					}
					else if (numValueObjects == 10)
					{
						_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7], valueObjects[8], valueObjects[9]);
					}
					else
					{
						_listener.apply(null, valueObjects);
					}
				}
			}
		}
		
		private function debugExecute(valueObjects:Array, numValueObjects:int):void
		{
			var msg:String = null;
			try
			{
				if (numValueObjects == 0)
				{
					_listener();
				}
				else if (numValueObjects == 1)
				{
					_listener(valueObjects[0]);
				}
				else if (numValueObjects == 2)
				{
					_listener(valueObjects[0], valueObjects[1]);
				}
				else if (numValueObjects == 3)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2]);
				}
				else if (numValueObjects == 4)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3]);
				}
				else if (numValueObjects == 5)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4]);
				}
				else if (numValueObjects == 6)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5]);
				}
				else if (numValueObjects == 7)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6]);
				}
				else if (numValueObjects == 8)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7]);
				}
				else if (numValueObjects == 9)
				{
					_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7], valueObjects[8]);
				}
				else
				{
					_listener.apply(null, valueObjects);
				}
			}
			catch (err:Error)
			{
				var stack:String = err.getStackTrace();
				msg = "(" + err.errorID + ")" + err.name + ":" + err.message;
				throw err;
			}
			finally
			{
				if (msg)
				{
					_listener.call();
				}
			}
		}
		
		public function execute(valueObjects:Array):void 
		{
			if (!_enabled)
			{
				return;
			}
			if (_once)
			{
				remove();
			}
			if (_params && _params.length)
			{
				valueObjects = valueObjects.concat(_params);
			}
			const numValueObjects:int = _safelyExecute? _listener.length : valueObjects.length;
			if (_debug)
			{
				debugExecute(valueObjects, numValueObjects);
				return;
			}
			if (numValueObjects == 0)
			{
				_listener();
			}
			else if (numValueObjects == 1)
			{
				_listener(valueObjects[0]);
			}
			else if (numValueObjects == 2)
			{
				_listener(valueObjects[0], valueObjects[1]);
			}
			else if (numValueObjects == 3)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2]);
			}
			else if (numValueObjects == 4)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3]);
			}
			else if (numValueObjects == 5)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4]);
			}
			else if (numValueObjects == 6)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5]);
			}
			else if (numValueObjects == 7)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6]);
			}
			else if (numValueObjects == 8)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7]);
			}
			else if (numValueObjects == 9)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7], valueObjects[8]);
			}
			else
			{
				_listener.apply(null, valueObjects);
			}
		}
		
		public function remove():void 
		{
			_signal.remove(_listener);
		}
		
		public function execute1(value:Object):void 
		{
			if (!_enabled)
			{
				return;
			}
			if (_once)
			{
				remove();
			}
			var valueObjects:Array = [value];
			if (_params && _params.length)
			{
				valueObjects = valueObjects.concat(_params);
			}
			const numValueObjects:int = _safelyExecute? _listener.length : valueObjects.length;
			if (numValueObjects == 0)
			{
				_listener();
			}
			else if (numValueObjects == 1)
			{
				_listener(valueObjects[0]);
			}
			else if (numValueObjects == 2)
			{
				_listener(valueObjects[0], valueObjects[1]);
			}
			else if (numValueObjects == 3)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2]);
			}
			else if (numValueObjects == 4)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3]);
			}
			else if (numValueObjects == 5)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4]);
			}
			else if (numValueObjects == 6)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5]);
			}
			else if (numValueObjects == 7)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6]);
			}
			else if (numValueObjects == 8)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7]);
			}
			else if (numValueObjects == 9)
			{
				_listener(valueObjects[0], valueObjects[1], valueObjects[2], valueObjects[3], valueObjects[4], valueObjects[5], valueObjects[6], valueObjects[7], valueObjects[8]);
			}
			else
			{
				_listener.apply(null, valueObjects);
			}
		}
		
		public function get safelyExecute():Boolean 
		{
			return _safelyExecute;
		}
		
		public function set safelyExecute(value:Boolean):void 
		{
			_safelyExecute = value;
		}
		
	}

}